package com.motu.monstercity.server.game.logic;

import com.motu.data.UserLoginDevice;
import com.motu.monstercity.module.common.network.ResponseUtils;
import com.motu.monstercity.module.common.redis.RedisKey;
import com.motu.monstercity.module.common.utility.Constant;
import com.motu.monstercity.module.common.utility.EventBusConstant;
import com.motu.monstercity.protocol.Common;
import com.motu.monstercity.protocol.Common.PBUserData;
import com.motu.monstercity.protocol.Common.PBUserDetailInfo;
import com.motu.monstercity.protocol.CsGameSystem;
import com.motu.monstercity.protocol.CsGameSystem.CSGameSystemPushDataResponse;
import com.motu.monstercity.protocol.CsGameSystem.CSGameSystemRedPointResponse;
import com.motu.monstercity.server.game.base.AllParam;
import com.motu.monstercity.server.game.base.ProtoDataUtils;
import com.motu.monstercity.server.game.commondata.build.BuildConstant;
import com.motu.monstercity.server.game.commondata.iap.GrowthFund;
import com.motu.monstercity.server.game.commondata.iap.PrivilegeCardConstant;
import com.motu.monstercity.server.game.commondata.maintask.MainTaskConstant;
import com.motu.monstercity.server.game.commondata.partner.PartnerMain;
import com.motu.monstercity.server.game.commondata.skill.Skill;
import com.motu.monstercity.server.game.commondata.skill.SkillConstant;
import com.motu.monstercity.server.game.commondata.system.DecorateMain;
import com.motu.monstercity.server.game.commondata.system.SystemConstant;
import com.motu.monstercity.server.game.log.ThinkingDataManager;
import com.motu.monstercity.server.game.userdata.*;
import com.motu.vertx.module.utility.kafka.KafkaLogManager;
import com.motu.vertx.module.utility.main.MainService;
import com.motu.vertx.module.utility.model.EntityManager;
import com.motu.vertx.module.utility.model.Model;
import com.motu.vertx.module.utility.monitor.MonitorManager;
import com.motu.vertx.module.utility.redis.RedisTools;
import com.motu.vertx.module.utility.threadpool.DBLogManager;
import com.motu.vertx.module.utility.toolset.ErrorWord;
import com.motu.vertx.module.utility.toolset.TimeUtils;
import com.motu.vertx.module.utility.toolset.Tool;
import io.vertx.core.Future;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

public class GameUser{
    private static Logger logger = LoggerFactory.getLogger(GameUser.class);

    public static UserInfo getUserInfo(long userId) {
        return (UserInfo) EntityManager.getUniqueEntity(UserInfo.class, userId, false);
    }

    public static UserExtInfo getUserExtInfo(long userId) {
        return (UserExtInfo) EntityManager.getUniqueEntity(UserExtInfo.class, userId, false);
    }

    public static UserPower getUserPower(long userId) {
        return (UserPower) EntityManager.getUniqueEntity(UserPower.class, userId);
    }

    public static UserAffair getUserAffair(long userId) {
        return (UserAffair) EntityManager.getUniqueEntity(UserAffair.class, userId);
    }

	public static UserAdvideo getUserAdvideo(long userId) {
		return (UserAdvideo) EntityManager.getUniqueEntity(UserAdvideo.class, userId);
	}

    public static List<UserIapGiftPush> getUserIapGiftPushList(long userId) {
        List<UserIapGiftPush> list = new ArrayList<>();
        List<Model> modelList = EntityManager.getEntityList(UserIapGiftPush.class, userId);
        for (Model model : modelList) {
            list.add((UserIapGiftPush) model);
        }
        return list;
    }

    public static UserIapGiftPush getUserIapGiftPush(long userId, int giftId) {
        return (UserIapGiftPush) EntityManager.getEntity(UserIapGiftPush.class, userId, giftId);
    }

	public static UserThinkingData getUserThinkingData(long userId) {
		return (UserThinkingData) EntityManager.getUniqueEntity(UserThinkingData.class, userId);
	}

	/**
	 * 获取用户登录设备信息（把json转成实体类）
	 * @param userId
	 * @return
	 */
	public static UserLoginDevice getUserLoginDevice(long userId) {
		return UserLoginDevice.newInstance(getGateObj(userId));
	}

	// 获取网关对象（此方法不对外，请用getUserLoginDevice方法）
	private static JsonObject getGateObj(long userId) {
		String redisKey = RedisKey.getUserLoginDeviceKey(userId);
		String str = Future.await(RedisTools.get(redisKey));
		if (str == null || str.isEmpty()) {
			return null;
		}
		JsonObject gobj = new JsonObject(str);
		return gobj;
	}

	public static void kickUser(long userId, ErrorWord errorWord) {
		pushToUser(userId, new JsonObject().put("kickcode", errorWord.value));
	}

	// 推送PBUserData给客户端进行更新
	public static void pushPBUserData(long userId, CSGameSystemPushDataResponse.Builder response) {
		JsonObject jsonObject = ResponseUtils.getPushResponseData(response.build().toByteArray());
		pushToUser(userId, jsonObject);
	}

	/**
     * 服务端推送数据到单个用户
     * @param userId
     * @param jsonObject
     */
    public static void pushToUser(long userId, JsonObject jsonObject) {
		String redisKey = RedisKey.getUserGateKey(userId);
		String gateName = Future.await(RedisTools.get(redisKey));
		if (!Tool.isEmpty(gateName)) {
            String address = EventBusConstant.getAddress(EventBusConstant.GATE_RECEIVE) + "_" + gateName;
            EventBus eventBus = MainService.getVertx().eventBus();
            jsonObject.put("userid", userId);
            eventBus.send(address, jsonObject);
        }
    }

	// 给某个玩家推送数据
	public static void pushToUser(long userId, Object object) {
		CsGameSystem.CSGameSystemPushDataResponse.Builder response = CsGameSystem.CSGameSystemPushDataResponse.newBuilder();
		Common.PBUserData.Builder pbUserData = response.getUserBuilder();
		ProtoDataUtils.updatePBUserData(pbUserData, object);
		JsonObject jsonObject = ResponseUtils.getPushResponseData(response.build().toByteArray());// 广播给其他人的数据
		pushToUser(userId, jsonObject);
	}


	// 服务端给某个玩家推送提示信息  type = 1;// 类型1：行军助力，2-医院恢复助力 param，类型1：行军助力，2-医院恢复助力  [当前被帮助次数，可被帮助的次数上限]
	public static void pushToUserTips(long userId, int type, UserInfo userInfoFrom, Object... content) {
		CsGameSystem.CSGameSystemPushTipsResponse.Builder response = CsGameSystem.CSGameSystemPushTipsResponse.newBuilder();
		response.setType(type);
		response.setUserId(userInfoFrom.getId());
		response.setUserName(userInfoFrom.getUserName());
		if (content.length > 0) {
			for (int i = 0; i < content.length; i++) {
				response.addParam(content[i] + "");
			}
		}
		JsonObject jsonObject = ResponseUtils.getPushResponseData(response.build().toByteArray());// 广播给其他人的数据
		pushToUser(userId, jsonObject);
	}

	/**
	 * 推送充值成功信息给客户端
	 *
	 * @param userId 用户ID
	 * @param obj    充值信息
	 */
	public static void pushIapFinishToUser(long userId, JsonObject obj) {
		String redisKey = RedisKey.getUserGateKey(userId);
		String gateName = Future.await(RedisTools.get(redisKey));
		if (!Tool.isEmpty(gateName)) {
			String address = EventBusConstant.getAddress(EventBusConstant.GATE_RECEIVE) + "_" + gateName;
			logger.info("pushIapFinishToUser success userId:" + userId);
			EventBus eventBus = MainService.getVertx().eventBus();
			obj.put("userid", userId);
			eventBus.send(address, obj);
		} else {
			logger.error("pushIapFinishToUser failed userId:" + userId + " gateName is null");
		}
	}

	/**
	 * 判断某个玩家是否连接
	 */
	public static boolean isConnect(long userId) {
		String redisKey = RedisKey.getUserGateKey(userId);
		return Future.await(RedisTools.exists(redisKey));
	}

    /**
     * 是否被封号
     */
    public static boolean isBanned(UserExtInfo userExtInfo) {
        long curTime = TimeUtils.getCurTime();
        if (userExtInfo.getBannedTime() > curTime) {
            //判断角色封号结束时间
            return true;
        } else {
            return MonitorManager.isBanned(userExtInfo.getAccountId(), userExtInfo.getPlatform(), userExtInfo.getId(), userExtInfo.getDeviceId(), userExtInfo.getIp());
        }
    }

	/**
	 * 获取玩家的当前总战力, 总战力 * （10000 + addvalue） / 10000
	 * @param userId
	 * @param addValue 模块的加成数量，比如物资争夺，战斗鼓舞加40%， 则传4000；
	 * @return
	 */
	public static long countUserPower(long userId, int addValue) {
        UserPower userPower = getUserPower(userId);
		double totalPower = userPower.getPower();
		totalPower = totalPower * (10000 + addValue) / 10000;
		return (long)Math.floor(totalPower);
    }

	/**
	 * 计算干员的当前总战力, 基础战力 + 基础战力 * 加成（通用加成+模块加成） + 加的固定值
	 * @param userId
	 * @param partnerId 干员id
	 * @param userPower 传对象进来，避免多个干员时，重复取值
	 * @param addValue 模块的加成数量，比如物资争夺，战斗鼓舞加40%， 则传4000；
	 * @return
	 */
	public static long countPowerByPartner(long userId, int partnerId, UserPartner userPartner, UserPower userPower, int addValue) {
		if (userPartner == null) {
			userPartner = PartnerManager.getUserPartner(userId, partnerId);
		}
		if (userPartner == null) {
			return 0L;
		}

		double basePower = userPartner.takePowerBase();// 基础战力
		double powerAddPer = basePower * (userPartner.takeTotalAddPer(userPower) + userPower.takeTotalAddPer(userPartner) + addValue) / 10000;// 百分比加成
		long powerAdd2 = userPartner.takeTotalAddCv() + userPower.takeTotalAddCv(partnerId);// 固定值加成
		double curPower = basePower + powerAddPer + powerAdd2;
		return  (long) Math.floor(curPower);
	}

	/**
	 * 具体模块的实际总战力，有些技能加成会针对不同性格，需要重新计算
	 * @param userId
	 * @param userPower
	 * @param effectType  支持两种加成类型，如联盟乱斗，有4， 和61 这两种加成类型
	 * @param effectType2
	 * @return
	 */
	public static long countTotalPowerModule(long userId, UserPower userPower, int effectType, int effectType2) {
		UserSkillEffect userSkillEffect = SkillManager.getUserSkillEffect(userId, effectType);
		UserSkillEffect userSkillEffect2 = effectType2 == 0 ? null : SkillManager.getUserSkillEffect(userId, effectType2);
		if (userSkillEffect == null && userSkillEffect2 == null) {
			return userPower.getPower();
		}

		long total = 0;
		List<UserPartner> list = PartnerManager.getUserPartnerList(userId);
		for (UserPartner userPartner : list) {
			int skillAdd = SkillManager.getSkillMoudleAdd(userId, userSkillEffect, userPartner.getCharacterType());// 干员技能加成,秘书技能加成
			int skillAdd2 = SkillManager.getSkillMoudleAdd(userId, userSkillEffect2, userPartner.getCharacterType());// 干员技能加成,秘书技能加成
			long myPartnerPower = GameUser.countPowerByPartner(userId, userPartner.getPartnerId(), userPartner, userPower, skillAdd + skillAdd2);// 该干员的战力
			total += myPartnerPower;
		}
		return total;
	}


	/**
	 * 统计称号模块战力加成百分比，1000 表示加成10%
	 * @param userId
	 * @param effectType 1-干员战力加成百分比,2-城市总收益加成百分比,3-干员战力加成固定值
	 * @param userTitleList
	 * @return
	 */
	public static int countTitleAdd(long userId, int effectType, long checkTime, List<UserTitle> userTitleList) {
		if (userTitleList == null) {
			userTitleList = GameDataManager.getUserTitleList(userId);
		}

		int total = 0;
		for (UserTitle userTitle : userTitleList) {
			if (userTitle.isExpired(checkTime)) {
				continue;// 已经过期了
			}
			DecorateMain decorateMain = GameDataManager.getDecorateMain(userTitle.getDecorateId());
			if (decorateMain == null) {
				continue;
			}
			if (decorateMain.getEffectType() == effectType) {
				total += decorateMain.getEffectValue();
			}
		}

		return total;
	}

	/**
	 * 根据用户id，获取用户展示数据
	 */
	public static UserShow getUserShow(long userId) {
		UserShow userShow = (UserShow) EntityManager.getUniqueEntity(UserShow.class, userId, false);
		if (userShow == null) {// redis没有数据,则重新生成
			UserInfo userInfo = GameUser.getUserInfo(userId);
			if (userInfo != null) {
				userShow = GameUser.updateUserShow(userInfo, null);
			}
		}
		return userShow;
	}

	/**
	 * 更新用户展示数据
	 */
	public static UserShow updateUserShow(UserInfo userInfo, UserUnion userUnion) {
		long userId = userInfo.getId();
		UserShow userShow = (UserShow) EntityManager.getUniqueEntity(UserShow.class, userId);// 没有则创建
		userShow.putUserName(userInfo.getUserName());
		userShow.putLevel(userInfo.getLevel());
		userShow.putIcon(userInfo.getIcon());
		userShow.putIconFrame(userInfo.getIconFrame());
		userShow.putServerId(userInfo.getServerId());
		userShow.putVip(userInfo.getVip());
		userShow.putTitleId(userInfo.getTitleId());
		userShow.putBubbleId(userInfo.getBubbleId());

		UserCityInfo userCityInfo = BuildManager.getUserCityInfo(userId);
		userShow.putCityName(userCityInfo.getCityName());
		userShow.putPartnerNum(PartnerManager.countPartnerNum(userId));// 干员数量

		UserPower userPower = GameUser.getUserPower(userId);
		userShow.putPower(userPower.getPower());
		userShow.putEarn(userPower.getEarn());

		if (userUnion == null) {
			userUnion = UnionManager.getUserUnion(userId);
		}
		if (userUnion != null && userUnion.getUnionId() > 0) {
			userShow.putUnionId(userUnion.getUnionId());
			UnionInfo unionInfo = UnionManager.getUnionInfo(userUnion.getUnionId());
			if (unionInfo != null) {
				userShow.putUnionName(unionInfo.getName());
			}
		} else {// 退出联盟
			userShow.putUnionId(0);
			userShow.putUnionName("");
		}

		userShow.update();
		return userShow;
	}

    // 查看玩家的详细信息
    public static PBUserDetailInfo.Builder takeUserDetailInfoBuilder(long userId) {
        PBUserDetailInfo.Builder builder = PBUserDetailInfo.newBuilder();
		UserShow userShow = getUserShow(userId);
		UserPower userPower = getUserPower(userId);
		builder.setUserShow(userShow.takeInitBuilder());

        return builder;
    }

	/**
	 * 处理玩家下线
	 * @param userId
	 * @param socketTime
	 */
	public static void dealOffline(long userId, long socketTime) {
		try {
			UserInfo userInfo = GameUser.getUserInfo(userId);
			UserExtInfo userExtInfo = GameUser.getUserExtInfo(userId);
			UserLoginDevice userLoginDevice = GameUser.getUserLoginDevice(userId);// 用户登录设备信息

			if (userInfo != null && userExtInfo != null) {
				long curTime = TimeUtils.getCurTime();
				//设置离线时间
				userExtInfo.putOfflineTime(curTime);
				userExtInfo.update();
				long onlineTime = TimeUtils.getTimeDiff(socketTime);
				logger.info("#### dealOffline userid:" + userId + " onlineTime:" + onlineTime);
				updateUserOnlineTime(userId, onlineTime, TimeUtils.getStartTimeOfDay(curTime));

				UserMonsterTideInfo userMonsterTideInfo = FightManager.getUserMonsterTiedInfo(userId);
				int monsterTideId = userMonsterTideInfo == null ? 0 : userMonsterTideInfo.getNextMonsterTideId();// 兽潮id
				UserThinkingData userThinkingData = GameUser.getUserThinkingData(userId);
				// 发送数数登出事件
				ThinkingDataManager.pushLogoutEvent(userInfo , onlineTime,userExtInfo.getLoginDayCount(), userThinkingData, monsterTideId);
				//数数SDK登出用户数据
				ThinkingDataManager.pushUserLogoutData(userInfo,userLoginDevice,userExtInfo.getLoginDayCount(),monsterTideId);
				//数数SDK登出累计游戏时长
				ThinkingDataManager.pushLogoutSessionTime(userId, onlineTime);

				userThinkingData.refreshData();

			} else {
				logger.error("#### dealOffline error! userid:" + userId);
			}
		} catch (Exception e) {
			DBLogManager.addServerCrashLog(userId, Tool.getException(e));
			throw e;
		}
	}

	/***
	 * 新增一条登录日志信息，每个用户每天只存一条
	 * @param loginDate 登录时当天00:00:00的时间戳
	 */
	public static void addUserLoginLog(int serverId, long userId, int level, int vip, int platform, long loginDate) {
		String sql = "INSERT INTO user_login_log2(server_id,user_id,level,vip,platform,login_count,login_date)" +
				" VALUES(?,?,?,?,?,?,?);";
		JsonArray params = new JsonArray();
		params.add(serverId);
		params.add(userId);
		params.add(level);
		params.add(vip);
		params.add(platform);
		params.add(1);
		params.add(loginDate);
		KafkaLogManager.addGameLog(sql, params, DBLogManager.DBTYPE_GAME);
	}

	/***
	 * 更新用户登录日志中的在线总时长信息
	 * @param userId
	 * @param onlineTime 在线时长
	 * @param loginDate 登录时当天00:00:00的时间戳
	 */
	public static void updateUserOnlineTime(long userId, long onlineTime, long loginDate) {
		String sql = "UPDATE user_login_log2 SET online_time = online_time + ? WHERE user_id = ? AND login_date = ?;";
		JsonArray params = new JsonArray();
		params.add(onlineTime);
		params.add(userId);
		params.add(loginDate);
		KafkaLogManager.addGameLog(sql, params, DBLogManager.DBTYPE_GAME);
	}

	/**
	 * 更新用户登录日志中的登录次数
	 * @param userId
	 * @param loginDate 登录时当天00:00:00的时间戳
	 */
	public static void updateUserLoginCount(long userId, long loginDate) {
		String sql = "UPDATE user_login_log2 SET login_count = login_count +1" +
				" WHERE user_id = ? AND login_date = ?;";
		JsonArray params = new JsonArray();
		params.add(userId);
		params.add(loginDate);
		KafkaLogManager.addGameLog(sql, params, DBLogManager.DBTYPE_GAME);
	}

	/**
	 * 重算userpower的字段power_add_title_per，power_add_world_cv，earn_add_secr_per，earn_add_bank_per，earn_add_decorate_per，earn_add_cave_per
	 */
	public static void refreshUserPower(UserInfo userInfo, UserPower userPower, UserAffair userAffair, List<UserPartner> partnerList, List<UserSecretary> secretaryList, List<UserBuild> buildList)
	{
		long userId = userInfo.getId();
		// 特权卡加成
		int pricardAdd = IapManager.takePrivilegeValueByType(userId, "earn_num");// 特权卡的加成 500 表示加成5%
		if (pricardAdd != userPower.getPricardAdd()) {
			userPower.putPricardAdd(pricardAdd);
		}

		List<UserTitle> userTitleList = GameDataManager.getUserTitleList(userId);
		// 称号加成
		int titleAddPowerCv = GameUser.countTitleAdd(userId, SystemConstant.DECORATE_TITLE_EFFECT_TYPE_3, TimeUtils.getCurTime(), userTitleList);//干员战力加成固定值
		if (titleAddPowerCv != userPower.getPowerAddTitleCv()) {
			userPower.putPowerAddTitleCv(titleAddPowerCv);
		}
		int titleAddPowerPer = GameUser.countTitleAdd(userId, SystemConstant.DECORATE_TITLE_EFFECT_TYPE_1, TimeUtils.getCurTime(), userTitleList);//干员战力加成百分比
		if (titleAddPowerPer != userPower.getPowerAddTitlePer()) {
			userPower.putPowerAddTitlePer(titleAddPowerPer);
		}
		int titleAddEarnPer = GameUser.countTitleAdd(userId, SystemConstant.DECORATE_TITLE_EFFECT_TYPE_2, TimeUtils.getCurTime(), userTitleList);//城市总收益加成百分比
		if (titleAddEarnPer != userPower.getEarnAddTitlePer()) {
			userPower.putEarnAddTitlePer(titleAddEarnPer);
		}


		// 大世界雷达加战力固定值
		UserBuild userBuild = BuildManager.getUserBuild(userId, BuildConstant.BUILD_ID_RADAR);
		if (userBuild != null) {
			long radarAdd = userBuild.takeRadarAdd();
			if (radarAdd != userPower.getPowerAddWorldCv()) {
				userPower.putPowerAddWorldCv(radarAdd);
			}
		}

		//  光环技能对战力的加成百分比
		String powerAddHalo = getPowerAddHalo(partnerList, secretaryList);
		if (!powerAddHalo.equals(userPower.getPowerAddHaloPer())) {
			userPower.putPowerAddHaloPer(powerAddHalo);
		}

		//  秘书对城市收益的加成
		String earnAddSecr = SecretaryManager.countEarnAddSecr(secretaryList);
		if (!earnAddSecr.equals(userPower.getEarnAddSecrPer())) {
			userPower.putEarnAddSecrPer(earnAddSecr);
		}

		// 银行
		int bankAddEarn = BuildManager.takeBankAddEarn(getUserBuildBank(buildList));// 银行的城市收益加成
		if (bankAddEarn != userPower.getEarnAddBankPer()) {
			userPower.putEarnAddBankPer(bankAddEarn);
		}

		// 装饰类建筑的加成，地标类建筑的加成
		String earnAddDecorate = BuildManager.getEarnAddDecorate(buildList);
		if (!earnAddDecorate.equals(userPower.getEarnAddDecoratePer())) {
			userPower.putEarnAddDecoratePer(earnAddDecorate);
		}

		// 地下洞窟的加成
		UserCaveLocation userCaveLocation = CaveManager.getUserCaveLocation(userInfo.getId());
		int addValue = userCaveLocation.takeEarnAdd();
		if (addValue != userPower.getEarnAddCavePer()) {
			userPower.putEarnAddCavePer(addValue);
		}

		// 兽潮的加成百分比
		int monsterTideAdd = userAffair.takeMonsterTideAdd();
		if (monsterTideAdd != userPower.getEarnAddMonsterPer()) {
			userPower.putEarnAddMonsterPer(monsterTideAdd);
		}

		// 美食攻略
		List<UserRestaurantFood> foodList = RestaurantManager.getUserRestaurantFoodList(userId);
		String earnAddFood = RestaurantManager.getEarnAddFood(foodList);
		if (!earnAddFood.equals(userPower.getEarnAddFoodPer())) {
			userPower.putEarnAddFoodPer(earnAddFood);
		}

		// 联盟地标建筑
		String powerAddUnion = UnionManager.getPowerAddUnionNew(userId);
		if (!powerAddUnion.equals(userPower.getPowerAddUnionPer())) {
			userPower.putPowerAddUnionPer(powerAddUnion);
		}

		// 联盟地标建筑固定值加成
		String powerAddUnionCv = UnionManager.getPowerAddUnionNewCv(userId);
		if (!powerAddUnionCv.equals(userPower.getPowerAddUnionCv())) {
			userPower.putPowerAddUnionCv(powerAddUnionCv);
		}

		// 联盟建筑
		String earnAddUnion = UnionManager.getEarnAddUnion(userId);
		if (!earnAddUnion.equals(userPower.getEarnAddUnionPer())) {
			userPower.putEarnAddUnionPer(earnAddUnion);
		}

		// 所有武器等级增加的上限 干员的专属技能，秘书的基因技能有
		int weaponLevel = SkillManager.countSkillFromAll(partnerList, secretaryList, SkillConstant.EFFECT_TYPE_12, 0);
		if (weaponLevel != userPower.getWeaponLevelMaxAdd()) {
			userPower.putWeaponLevelMaxAdd(weaponLevel);
		}

		// 已经获得的干员id列表
		JsonArray partnerIds = PartnerManager.getParterIds(partnerList);
		if (!partnerIds.toString().equals(userPower.getPartnerId())) {
			logger.info("###userpower partnerid info userid:" + userInfo.getId() + " partnerids:" + partnerIds);
			userPower.putPartnerId(partnerIds.toString());
		}

		// 已经解锁并摆放的商业建筑id 列表
		JsonArray buildIds = BuildManager.getBuildIds(buildList);
		if (!buildIds.toString().equals(userPower.getBuildId())) {
			userPower.putBuildId(buildIds.toString());
		}
	}

	// 登录时重算玩家的战力
	public static void reCountPower(PBUserData.Builder pbUserData, UserInfo userInfo, UserPower userPower, List<UserPartner> partnerList, List<UserSecretary> userSecretaryList) {
		long totalPower = 0L;// 玩家的总战力,所有干员的战力之和 包括了称号加成，联盟地标加成，雷达固定值加成等

		for (UserPartner userPartner : partnerList) {
			initPartnerPower(userInfo, userPower, userPartner, userSecretaryList);
			userPartner.update();
			ProtoDataUtils.updatePBUserData(pbUserData, userPartner, true);// 下发给客户端
			totalPower += userPartner.getTotalPower();
		}

		if (totalPower != userPower.getPower()) {
			userPower.updatePower(pbUserData, userInfo, totalPower);
		}
	}

	// 登录时重算玩家的城市收益
	public static void reCountEarn(PBUserData.Builder pbUserData, UserInfo userInfo, UserPower userPower, List<UserBuild> userBuildList)
	{
		long totalEarn = 0L;// 玩家的所有商业建筑的总收益
		int bankAddEarn = BuildManager.takeBankAddEarn(getUserBuildBank(userBuildList));// 银行的城市收益加成
		for (UserBuild userBuild : userBuildList) {
			if (userBuild.isBusinessBuild()) {
				if (userBuild.isPlace()) {// 商业建筑且已放置才需要重算城市收益) {
					initBuildEarn(userBuild, userPower, userBuildList);
					totalEarn += userBuild.getTotalEarn();
				} else {
					userBuild.putTotalEarn(0);//未摆放的把城市收益置为0
				}
				userBuild.update();
				ProtoDataUtils.updatePBUserData(pbUserData, userBuild, true);// 下发给客户端
			}
		}
		long addEarn = totalEarn - userPower.getBuildEarn();
		if (addEarn != 0) {
			userPower.addBuildEarn(pbUserData, userInfo, addEarn);// // 增量更新建筑的总收益
		} else {
			userPower.handleEarnChange(pbUserData, userInfo);// 更新总收益 总收益=（建筑收益+后代收益）*（1+特权卡收益加成+永久收益加成）
		}
	}

	// 重算商业建筑的城市收益
	public static void initBuildEarn(UserBuild userBuild, UserPower userPower, List<UserBuild> buildList) {
		// 委派的干员加成百分比
		int partnerAdd = userBuild.takePartnerEarnAdd();
		userBuild.putPartnerAdd2(partnerAdd);

		long newEarn = userBuild.countTotalEarn(userPower);// 重算后的总收益
		userBuild.putTotalEarn(newEarn);
	}

	// 重算干员的战力，只重算武器加成，干员基础技能加成，秘书羁绊技能加成
	public static void initPartnerPower(UserInfo userInfo, UserPower userPower, UserPartner userPartner, List<UserSecretary> userSecretaryList) {
		// 武器加成 有加资质和加百分比
		if (userPartner.getWeaponDbid() > 0) {
			UserWeapon userWeapon = PartnerManager.getUserWeapon(userInfo.getId(), userPartner.getWeaponDbid());
			if (userWeapon != null) {
				int weaponAdd = userPartner.takePowerWeapon(userWeapon);// 武器给干员的战力加成 返回百分几
				userPartner.putWeaponAdd2(weaponAdd);// 加的百分比
				userPartner.putWeaponTalent(userWeapon.getTalent());// 加的资质
			}
		}

		// 秘书的羁绊技能加成
		long secrAdd = 0L;// 加固定值
		int secrAdd2 = 0;// 加百分比
 		for (UserSecretary userSecretary : userSecretaryList) {
			 if (Tool.isInList(userSecretary.takePartnerIds(), userPartner.getPartnerId())) {// 该干员有羁绊关系的秘书
				 secrAdd += userSecretary.countPatronSkillAdd(SkillConstant.EFFECT_TYPE_31);// 羁绊技能，只有秘书才有 羁绊门客战力+定值
				 secrAdd2 += userSecretary.countPatronSkillAdd(SkillConstant.EFFECT_TYPE_32);// 羁绊技能，只有秘书才有 羁绊门客战力+%
			 }
		}
		userPartner.putSecrAdd(secrAdd);
		userPartner.putSecrAdd2(secrAdd2);

		long newPower = GameUser.countPowerByPartner(userInfo.getId(), userPartner.getPartnerId(), userPartner, userPower, 0);// 该干员的战力
		userPartner.putTotalPower(newPower);
	}

	// 获取银行的对象
	public static UserBuild getUserBuildBank(List<UserBuild> buildList) {
		for (UserBuild userBuild : buildList) {
			if (userBuild.getBuildId() == BuildConstant.BUILD_ID_BANK) {
				return userBuild;
			}
		}
		return null;
	}

	// 推送红点提示
	public static void sendRedPointPrompt(UserInfo userInfo, UserExtInfo userExtInfo, int promptType, Object... params) {
		long userId = userInfo.getId();
		boolean hasRedPoint = false;// 是否有红点
		CSGameSystemRedPointResponse.Builder builder = CSGameSystemRedPointResponse.newBuilder();
		builder.setPromptType(promptType);

		// 初始化的红点需要下发的哪些红点
		if (promptType == SystemConstant.RED_POINT_TYPE_INIT) {
			hasRedPoint = checkRedPointPromptInit(builder, userInfo, userExtInfo);
		} else if (promptType == SystemConstant.RED_POINT_TYPE_FLORIST) {
			CsGameSystem.RedPoint_Florist.Builder floristBuilder = CsGameSystem.RedPoint_Florist.newBuilder();
			floristBuilder.setTask(true);
			builder.setFlorist(floristBuilder);
			hasRedPoint = true;
		} else if (promptType == SystemConstant.RED_POINT_RANDOM_EVENT) {
			if (params.length > 0) {
				UserOnlineEvent event = (UserOnlineEvent) params[0];
				CsGameSystem.RedPoint_Event.Builder eventBuilder = CsGameSystem.RedPoint_Event.newBuilder();
				eventBuilder.setOnlineEvent(event.takeInitBuilder());
				builder.setEvent(eventBuilder);
				hasRedPoint = true;
			}
		} else if (promptType == SystemConstant.RED_POINT_RANKACT_RISE) {
			int groupId = (int) params[0];
			int rankType = (int) params[1];
			long oldRank =Long.parseLong(params[2].toString());
			long newRank = Long.parseLong(params[3].toString());
			CsGameSystem.RedPoint_RankactRise.Builder rankActRiseBuilder = CsGameSystem.RedPoint_RankactRise.newBuilder();
			rankActRiseBuilder.setGroupId(groupId);
			rankActRiseBuilder.setRankType(rankType);
			rankActRiseBuilder.setOldRank(oldRank);
			rankActRiseBuilder.setNewRank(newRank);
			builder.setRankactRise(rankActRiseBuilder);
			hasRedPoint = true;
		} else if (promptType == SystemConstant.RED_POINT_RANKACT_RED_POINT) {
			int subType = (int) params[0];
			int configId = (int) params[1];
			List<Integer> rdArray = (List<Integer>) params[2];
			CsGameSystem.RedPoint_RankactReward.Builder rankActRewardBuilder = CsGameSystem.RedPoint_RankactReward.newBuilder();
			switch (subType) {
				case SystemConstant.RED_POINT_RANKACT_SUB_TYPE_TASK:
					rankActRewardBuilder.addAllTaskGroups(rdArray);
					break;
				case SystemConstant.RED_POINT_RANKACT_SUB_TYPE_RECHARGE:
					rankActRewardBuilder.addAllRechargeTasks(rdArray);
				break;
			}
			rankActRewardBuilder.setConfigId(configId);
			builder.setRankactReward(rankActRewardBuilder);
			hasRedPoint = true;
		} else if (promptType == SystemConstant.RED_POINT_UNION_BOX) {
			UnionInfo unionInfo = (UnionInfo) params[0];
			if (unionInfo != null) {
				long unionId = unionInfo.getId();
				CsGameSystem.RedPoint_Union.Builder unionBuilder = builder.getUnionBuilder();
				if (UnionManager.isHaveUnionGiftRed(unionId,userId, unionBuilder,unionInfo)) {
					hasRedPoint =true;
				}
			}
		} else if (promptType == SystemConstant.RED_POINT_BUDDY_APPLY) {
			CsGameSystem.RedPoint_buddy.Builder redPoint = builder.getBuddyBuilder();
			redPoint.setApply(true);
			builder.setBuddy(redPoint);
			hasRedPoint = true;

		} else if (promptType == SystemConstant.RED_POINT_UNION) {
			if (UnionManager.checkRedPoint(userInfo, builder)) {
				hasRedPoint = true;
			}
		}


		if (hasRedPoint) {
			logger.info("userId: {} redPoint: {}", userId, Tool.protobufToJson(builder));
			JsonObject jsonObject = ResponseUtils.getRedpointResponseData(builder.build().toByteArray());
			GameUser.pushToUser(userId, jsonObject);
		}
	}

	// 初始化的红点需要下发的哪些红点
	private static boolean checkRedPointPromptInit(CSGameSystemRedPointResponse.Builder builder, UserInfo userInfo, UserExtInfo userExtInfo) {
		boolean hasRedPoint = false;
		if (MailManager.checkRedPoint(builder, userInfo)) {
			hasRedPoint = true;// 有未查看的邮件就提示红点
		}
		if (FloristManager.checkRedPoint(userInfo, builder)) {
			hasRedPoint = true;
		}
		if (ActDaysManager.checkRedPoint(userInfo, userExtInfo, builder)) {
			hasRedPoint = true;
		}
		if (PartnerManager.checkRedPoint(builder, userInfo)) {
			hasRedPoint = true;
		}
		if (RankManager.checkRedPointWorship(builder, userInfo)) {
			hasRedPoint = true;
		}
		if (MainTaskManager.checkRedPointHonor(builder, userInfo)) {
			hasRedPoint = true;
		}
		if (BagManager.checkRedPointBag(builder, userInfo)) {
			hasRedPoint = true;
		}
		if (DrawManager.checkRedPointTigerDraw(builder, userInfo)) {
			hasRedPoint = true;
		}
		if (ChildManager.checkRedPointStudy(builder, userInfo)) {
			hasRedPoint = true;
		}
		if (DatingManager.checkRedPointDating(builder, userInfo)) {
			hasRedPoint = true;
		}

		if (SecretaryManager.checkRedPoint(userInfo, builder)) {
			hasRedPoint = true;
		}

		if (IapManager.checkRedPoint(userInfo, builder)) {
			hasRedPoint = true;
		}

		if (ActManager.checkRedPoint(userInfo, builder)) {
			hasRedPoint = true;
		}

		if (ActConventionManager.checkRedPoint(userInfo, builder)) {
			hasRedPoint = true;
		}

		if (UnionManager.checkRedPoint(userInfo, builder)) {
			hasRedPoint = true;
		}

		if (BuddyManager.checkRedPoint(userInfo, builder)) {
			hasRedPoint = true;
		}

		if (RankActManager.checkRedPoint(userInfo, builder)) {
			hasRedPoint = true;
		}

		if (WorldManager.checkRedPoint(userInfo, builder)) {
			hasRedPoint = true;
		}

		return hasRedPoint;
	}

	// 校验视频广告是否正常完成观看
	public static boolean checkAdVideo(UserAdvideo userAdvideo, String adCode) {
		int functionClientId = 1;//  客户端功能开关，是否关闭广告
		JsonObject jsonObject = GameDataManager.getFunctionClient(functionClientId);
		if (jsonObject != null) {// 广告开关有配置，且配置为关闭广告 跳过校验，直接发放奖励
			if (jsonObject.getInteger("open") == 0) {
				return true;
			}
		}

		int skipAd = IapManager.takePrivilegeValueByType(userAdvideo.getId(), PrivilegeCardConstant.TYPE_SKIN_AD);
		if (skipAd > 0) {
			return true;// 购买了特权卡跳过广告校验
		}
		if (userAdvideo.getAdStartTime() == 0 || Tool.isEmpty(adCode)) {
			return false;// 未开始观看广告
		}
		long difftime = TimeUtils.getTimeDiff(userAdvideo.getAdStartTime());
		if (difftime >= AllParam.VIDEO_MIN_TIME_TYPE_1 && adCode.equalsIgnoreCase(userAdvideo.getAdCode())) {
			return true;
		} else {
			return false;
		}
	}

	// 同步各种有时效的加成效果，称号，兽潮，地下洞窟被打
	public static void handleSyncData(PBUserData.Builder pbUserData, UserInfo userInfo, UserPower userPower, UserAffair userAffair) {
		long userId = userInfo.getId();
		boolean isUpdatePower = false;// 更新战力
		boolean isUpdateEarn = false;// 更新收益

		// 特权卡加成
		int pricardAdd = IapManager.takePrivilegeValueByType(userId, "earn_num");// 特权卡的加成 500 表示加成5%
		if (pricardAdd != userPower.getPricardAdd()) {
			userPower.putPricardAdd(pricardAdd);
			isUpdateEarn = true;
		}

		// 称号加成
		List<UserTitle> userTitleList = GameDataManager.getUserTitleList(userId);
		int titleAddPowerCv = GameUser.countTitleAdd(userId, SystemConstant.DECORATE_TITLE_EFFECT_TYPE_3, TimeUtils.getCurTime(), userTitleList);//干员战力加成固定值
		if (titleAddPowerCv != userPower.getPowerAddTitleCv()) {
			userPower.putPowerAddTitleCv(titleAddPowerCv);
			isUpdatePower = true;
		}
		int titleAddPowerPer = GameUser.countTitleAdd(userId, SystemConstant.DECORATE_TITLE_EFFECT_TYPE_1, TimeUtils.getCurTime(), userTitleList);//干员战力加成百分比
		if (titleAddPowerPer != userPower.getPowerAddTitlePer()) {
			userPower.putPowerAddTitlePer(titleAddPowerPer);
			isUpdatePower = true;
		}
		int titleAddEarnPer = GameUser.countTitleAdd(userId, SystemConstant.DECORATE_TITLE_EFFECT_TYPE_2, TimeUtils.getCurTime(), userTitleList);//城市总收益加成百分比
		if (titleAddEarnPer != userPower.getEarnAddTitlePer()) {
			userPower.putEarnAddTitlePer(titleAddEarnPer);
			isUpdateEarn = true;
		}

		// 兽潮加成
		int monsterTideAdd = userAffair.takeMonsterTideAdd();
		if (monsterTideAdd != userPower.getEarnAddMonsterPer()) {
			userPower.putEarnAddMonsterPer(monsterTideAdd);
			isUpdateEarn = true;
		}

		// 地下洞窟的加成
		UserCaveLocation userCaveLocation = CaveManager.getUserCaveLocation(userInfo.getId());
		int addValue = userCaveLocation.takeEarnAdd();
		if (addValue != userPower.getEarnAddCavePer()) {
			userPower.putEarnAddCavePer(addValue);
			isUpdateEarn = true;
		}

		// 联盟建筑
		String earnAddUnion = UnionManager.getEarnAddUnion(userId);
		if (!earnAddUnion.equals(userPower.getEarnAddUnionPer())) {
			userPower.putEarnAddUnionPer(earnAddUnion);
			isUpdateEarn = true;
		}

		// 联盟地标建筑
		String powerAddUnion = UnionManager.getPowerAddUnionNew(userId);
		if (!powerAddUnion.equals(userPower.getPowerAddUnionPer())) {
			userPower.putPowerAddUnionPer(powerAddUnion);
			isUpdatePower = true;
		}

		// 联盟地标建筑固定值加成
		String powerAddUnionCv = UnionManager.getPowerAddUnionNewCv(userId);
		if (!powerAddUnionCv.equals(userPower.getPowerAddUnionCv())) {
			userPower.putPowerAddUnionCv(powerAddUnionCv);
			isUpdatePower = true;
		}


		if (isUpdatePower) {
			List<UserPartner> partnerList = userPower.takeUserPartnerList(0);
			PartnerManager.batchUpdatePartnerPower(pbUserData, userInfo, userPower, partnerList);
		} else if (isUpdateEarn) {
			List<UserBuild> buildList = userPower.takeUserBuildList(0);
			BuildManager.batchUpdateBuildEarn(pbUserData, userInfo, userPower, buildList);
		}
	}

	// 重算干员，秘书技能在各个模块的总加成值 全量更新userSkillEffect，并下发给客户端
	public static void handleRecountSkillEffect(PBUserData.Builder pbUserData, long userId, List<UserPartner> partnerList, List<UserSecretary> secrList) {
		int[] list = SkillConstant.SKILL_EFFECT_LIST;
		for (int i=0; i<list.length; i++) {
			int effectType = list[i];
			int value0 = SkillManager.countSkillFromAll(partnerList, secrList, effectType, 0);
			int value1 = SkillManager.countSkillFromAll(partnerList, secrList, effectType, Constant.CHARACTER_TYPE_1);
			int value2 = SkillManager.countSkillFromAll(partnerList, secrList, effectType, Constant.CHARACTER_TYPE_2);
			int value3 = SkillManager.countSkillFromAll(partnerList, secrList, effectType, Constant.CHARACTER_TYPE_3);
			int value4 = SkillManager.countSkillFromAll(partnerList, secrList, effectType, Constant.CHARACTER_TYPE_4);
			int value5 = SkillManager.countSkillFromAll(partnerList, secrList, effectType, Constant.CHARACTER_TYPE_5);
			JsonArray jsonArray = SkillManager.createSkillEffectArray();
			jsonArray.set(0, value0);
			jsonArray.set(Constant.CHARACTER_TYPE_1, value1);
			jsonArray.set(Constant.CHARACTER_TYPE_2, value2);
			jsonArray.set(Constant.CHARACTER_TYPE_3, value3);
			jsonArray.set(Constant.CHARACTER_TYPE_4, value4);
			jsonArray.set(Constant.CHARACTER_TYPE_5, value5);
			SkillManager.updateSkillEffect(pbUserData, userId, effectType, jsonArray);
		}
	}

	// 统计所有干员的光环技能对战力的加成

	public static String getPowerAddHalo(List<UserPartner> partnerList, List<UserSecretary> secretaryList) {
		JsonArray jsonArray = SkillManager.createSkillEffectArray();
		int value0 = 0;
		int value1 = 0;
		int value2 = 0;
		int value3 = 0;
		int value4 = 0;
		int value5 = 0;
		for (UserPartner userPartner : partnerList) {
			PartnerMain partnerMain = PartnerManager.getPartnerMain(userPartner.getPartnerId());
			if (partnerMain == null) {
				continue;
			}
			int[] skillList = partnerMain.takeSkillHaloList();
			if (skillList == null || skillList.length == 0) {
				continue;
			}
			//System.out.println("partnerid:" + userPartner.getPartnerId());
			JsonArray skillHaloLevel = userPartner.getSkillHaloLevelArray();// 光环技能升级情况
			for (int i=0; i<skillList.length; i++) {
				int skillId = skillList[i];// 技能id
				int level = skillHaloLevel.getInteger(i);
				Skill skill = SkillManager.getSkill(skillId);
				//System.out.println("skillid:" + skillId + " level:" + level);
				if (skill == null || skill.getEffectType() != SkillConstant.EFFECT_TYPE_45) {// 只统计45 这个类型
					continue;
				}
				int addValue = skill.countTotalAdd(level);
				//System.out.println("addValue:" + addValue  + " param: " + skill.getEffectParam());
				if (skill.getEffectParam() == 0) {
					value0 += addValue;
				} else if (skill.getEffectParam() == Constant.CHARACTER_TYPE_1) {
					value1 += addValue;
				} else if (skill.getEffectParam() == Constant.CHARACTER_TYPE_2) {
					value2 += addValue;
				} else if (skill.getEffectParam() == Constant.CHARACTER_TYPE_3) {
					value3 += addValue;
				} else if (skill.getEffectParam() == Constant.CHARACTER_TYPE_4) {
					value4 += addValue;
				} else if (skill.getEffectParam() == Constant.CHARACTER_TYPE_5) {
					value5 += addValue;
				}
			}
		}
		jsonArray.set(0, value0);
		jsonArray.set(Constant.CHARACTER_TYPE_1, value1);
		jsonArray.set(Constant.CHARACTER_TYPE_2, value2);
		jsonArray.set(Constant.CHARACTER_TYPE_3, value3);
		jsonArray.set(Constant.CHARACTER_TYPE_4, value4);
		jsonArray.set(Constant.CHARACTER_TYPE_5, value5);

		return jsonArray.toString();
	}
}
